/**
 * Created on 2007-05-17 18:32
 */
package game.frames;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

/**
 * @author David Wallin
 */
public class ControlChangeFrame extends BasicFrame
{
	/**
	 * Serializable interface forces this to be declared
	 */
	private static final long				serialVersionUID = 1489801909192678725L;
	private static final String				LEAVE_SCREEN_WHILE_UNSET = "You can not leave and save changes\nwhile one or more buttons are unset";
	private JLabel							m_Header;
	
	private JButton							m_UpperLeft;
	private JButton							m_UpperRight;
	private JButton							m_MiddleLeft;
	private JButton							m_MiddleRight;
	private JButton							m_LowerLeft;
	private JButton							m_LowerRight;
	private JButton							m_Rotate;
	private JButton							m_DropDown;
	private JButton							m_Pause;
	private JButton							m_Quit;
	private JButton							m_EditedControl;
	
	private JButton							m_Defaults;
	private JButton							m_BackAbandon;
	private JButton							m_BackSave;
	
	private JTextArea						m_Info;
	
	private HashMap<JButton, Integer>		m_CurrentMapping;
	private HashMap<JButton, Integer>		m_LastMapping;
	private HashMap<JButton, Integer>		m_DefaultMapping;
	private ArrayList<JButton>				m_Buttons;
	
	/**
	 * 
	 */
	public ControlChangeFrame()
	{
		super(new GridBagLayout());
	}
	
	/* (non-Javadoc)
	 * @see frames.BasicFrame#initializeComponent()
	 */
	@Override
	protected void initializeComponent()
	{
		/*
		 * Instanciate all members
		 */
		m_Header = new JLabel("Control mapping");
		
		m_UpperLeft = new JButton();
		m_UpperRight = new JButton();
		m_MiddleLeft = new JButton();
		m_MiddleRight = new JButton();
		m_LowerLeft = new JButton();
		m_LowerRight = new JButton();
		m_Rotate = new JButton();
		m_DropDown = new JButton();
		m_Pause = new JButton();
		m_Quit = new JButton();
		m_EditedControl = null; //this should never be anything else then null or a copy of one of the 8 key code buttons
		
		m_Defaults = new JButton("Default");
		m_BackAbandon = new JButton("Cancel");
		m_BackSave = new JButton("OK!");
		
		m_Info = new JTextArea();
		
		m_CurrentMapping = new HashMap<JButton, Integer>();
		m_LastMapping = new HashMap<JButton, Integer>();
		m_DefaultMapping = new HashMap<JButton, Integer>();
		m_Buttons = new ArrayList<JButton>();
		
		/*
		 * Set the names of the 10 key code buttons for use when setting their labels
		 */
		m_UpperLeft.setName("Upper left: ");
		m_UpperRight.setName("Upper Right: ");
		m_MiddleLeft.setName("Middle left: ");
		m_MiddleRight.setName("Middle Right: ");
		m_LowerLeft.setName("Lower left: ");
		m_LowerRight.setName("Lower Right: ");
		m_Rotate.setName("Rotate: ");
		m_DropDown.setName("Drop down: ");
		m_Quit.setName("Quit: ");
		m_Pause.setName("Pause: ");
		m_Info.setText("                \n                \n                \n");
		m_Info.setPreferredSize(new Dimension(220, 50));
		
		/*
		 * Populate the default map
		 */
		m_DefaultMapping.put(m_UpperLeft, m_InputManager.getUpperLeftKeyCode());
		m_DefaultMapping.put(m_UpperRight, m_InputManager.getUpperRightKeyCode());
		m_DefaultMapping.put(m_MiddleLeft, m_InputManager.getMiddleLeftKeyCode());
		m_DefaultMapping.put(m_MiddleRight, m_InputManager.getMiddleRightKeyCode());
		m_DefaultMapping.put(m_LowerLeft, m_InputManager.getLowerLeftKeyCode());
		m_DefaultMapping.put(m_LowerRight, m_InputManager.getLowerRightKeyCode());
		m_DefaultMapping.put(m_Rotate, m_InputManager.getMiddleRotateKeyCode());
		m_DefaultMapping.put(m_DropDown, m_InputManager.getLowerDropDownKeyCode());
		m_DefaultMapping.put(m_Pause, m_InputManager.getPauseKeyCode());
		m_DefaultMapping.put(m_Quit, m_InputManager.getQuitKeyCode());
		/*
		 * Populate the list of the 10 key code buttons
		 */
		m_Buttons.add(m_UpperLeft);
		m_Buttons.add(m_UpperRight);
		m_Buttons.add(m_MiddleLeft);
		m_Buttons.add(m_MiddleRight);
		m_Buttons.add(m_LowerLeft);
		m_Buttons.add(m_LowerRight);
		m_Buttons.add(m_Rotate);
		m_Buttons.add(m_DropDown);
		m_Buttons.add(m_Pause);
		m_Buttons.add(m_Quit);
		
		/*
		 * Clone the 'current' and 'last' mapping maps
		 */
		m_CurrentMapping = this.getHashMapClone(m_DefaultMapping);
		m_LastMapping = this.getHashMapClone(m_DefaultMapping);
		
		/*
		 * Set the labels of the 10 key code buttons
		 */
		this.setButtonLabels();
		
		/*
		 * Add the action and key listeners
		 */
		m_UpperLeft.addActionListener(this);
		m_UpperRight.addActionListener(this);
		m_MiddleLeft.addActionListener(this);
		m_MiddleRight.addActionListener(this);
		m_LowerLeft.addActionListener(this);
		m_LowerRight.addActionListener(this);
		m_Rotate.addActionListener(this);
		m_DropDown.addActionListener(this);
		m_Pause.addActionListener(this);
		m_Quit.addActionListener(this);
		
		m_Defaults.addActionListener(this);
		m_BackAbandon.addActionListener(this);
		m_BackSave.addActionListener(this);
		
		m_UpperLeft.addKeyListener(this);
		m_UpperRight.addKeyListener(this);
		m_MiddleLeft.addKeyListener(this);
		m_MiddleRight.addKeyListener(this);
		m_LowerLeft.addKeyListener(this);
		m_LowerRight.addKeyListener(this);
		m_Rotate.addKeyListener(this);
		m_DropDown.addKeyListener(this);
		m_Pause.addKeyListener(this);
		m_Quit.addKeyListener(this);
		
		m_Defaults.addKeyListener(this);
		m_BackAbandon.addKeyListener(this);
		m_BackSave.addKeyListener(this);
		
		/*
		 * Graphic layout
		 */
		this.setBackground(Color.black);
		GridBagLayout gridBag = (GridBagLayout)this.getLayout();
		
		GridLayout keyCodeButtonsGrid = new GridLayout(5, 2);
		JPanel keyCodeButtonsPanel = new JPanel(keyCodeButtonsGrid);
		keyCodeButtonsPanel.setBackground(Color.black);
		keyCodeButtonsPanel.add(m_UpperLeft);
		keyCodeButtonsPanel.add(m_UpperRight);
		keyCodeButtonsPanel.add(m_MiddleLeft);
		keyCodeButtonsPanel.add(m_MiddleRight);
		keyCodeButtonsPanel.add(m_LowerLeft);
		keyCodeButtonsPanel.add(m_LowerRight);
		keyCodeButtonsPanel.add(m_Rotate);
		keyCodeButtonsPanel.add(m_DropDown);
		keyCodeButtonsPanel.add(m_Pause);
		keyCodeButtonsPanel.add(m_Quit);
		
		GridBagConstraints headerConstraints = new GridBagConstraints();
		headerConstraints.insets = new Insets(10, 0, 0, 0);
		headerConstraints.gridx = 3;
		headerConstraints.gridy = 0;
		headerConstraints.gridwidth = 1;
		headerConstraints.weightx = 0.5;
		
		GridBagConstraints keyCodeButtonsPanelConstraints = new GridBagConstraints();
		keyCodeButtonsPanelConstraints.insets = new Insets(10, 0, 0, 0);
		keyCodeButtonsPanelConstraints.gridx = 0;
		keyCodeButtonsPanelConstraints.gridy = 1;
		keyCodeButtonsPanelConstraints.gridwidth = 5;
		
		GridBagConstraints defaultsConstraints = new GridBagConstraints();
		defaultsConstraints.gridx = 3;
		defaultsConstraints.gridy = 2;
		defaultsConstraints.gridwidth = 1;
		defaultsConstraints.weightx = 0.5;
		
		GridBagConstraints backAbandonConstraints = new GridBagConstraints();
		backAbandonConstraints.gridx = 3;
		backAbandonConstraints.gridy = 3;
		backAbandonConstraints.gridwidth = 1;
		backAbandonConstraints.weightx = 0.5;
		
		GridBagConstraints backSaveConstraints = new GridBagConstraints();
		backSaveConstraints.gridx = 3;
		backSaveConstraints.gridy = 4;
		backSaveConstraints.gridwidth = 1;
		backSaveConstraints.weightx = 0.5;
		
		GridBagConstraints infoConstraints = new GridBagConstraints();
		infoConstraints.gridx = 1;
		infoConstraints.gridy = 5;
		infoConstraints.gridwidth = 3;
		infoConstraints.weightx = 1.0;
		
		Font f = new Font("Times", Font.BOLD, 14);
		m_Header.setFont(f);
		m_Header.setHorizontalAlignment(JLabel.CENTER);
		m_Header.setVerticalAlignment(JLabel.CENTER);
		m_Header.setBackground(Color.black);
		m_Header.setForeground(Color.gray);
		
		f = new Font("Times", Font.ITALIC, 12);
		m_Info.setFont(f);
		m_Info.setBackground(Color.black);
		m_Info.setForeground(Color.white);
		
		this.addComponent(m_Header, gridBag, headerConstraints);
		this.addComponent(keyCodeButtonsPanel, gridBag, keyCodeButtonsPanelConstraints);
		this.addComponent(m_Defaults, gridBag, defaultsConstraints);
		this.addComponent(m_BackAbandon, gridBag, backAbandonConstraints);
		this.addComponent(m_BackSave, gridBag, backSaveConstraints);
		this.addComponent(m_Info, gridBag, infoConstraints);
		
		this.doLayout();
	}
	
	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent event)
	{
		m_Info.setText("\n\n\n");
		m_EditedControl = null;
		Object source = event.getSource();
		
		if((source == m_UpperLeft) || (source == m_UpperRight) || (source == m_MiddleLeft) || (source == m_MiddleRight) ||
				(source == m_LowerLeft) || (source == m_LowerRight) || (source == m_Rotate) || (source == m_DropDown) ||
				(source == m_Pause) || (source == m_Quit))
		{
			m_EditedControl = (JButton)source;
		}
		
		if(source == m_Defaults)
		{
			m_CurrentMapping = this.getHashMapClone(m_DefaultMapping);
			this.setButtonLabels();
		}
		
		if(source == m_BackAbandon)
		{
			m_CurrentMapping = this.getHashMapClone(m_LastMapping);
			this.setButtonLabels();
			this.updateFrameSwitchListeners(Frames.OPTIONS);
		}
		
		if(source == m_BackSave)
		{
			if(allButtonsAreSet())
			{
				this.activateCurrentMapping();
				this.updateFrameSwitchListeners(Frames.OPTIONS);
			}
			else
			{
				m_Info.setText(LEAVE_SCREEN_WHILE_UNSET);
			}
		}
	}
	
	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	public void keyPressed(KeyEvent event)
	{
		if(m_EditedControl != null)
		{
			int keyCode = event.getKeyCode();
			releaseKeyCodeIfNeeded(keyCode);
			m_CurrentMapping.put(m_EditedControl, new Integer(keyCode));
			m_EditedControl = null;
			this.setButtonLabels();
		}
	}
	
	private boolean allButtonsAreSet()
	{
		boolean allAreSet = true;
		Iterator<JButton> it = m_Buttons.iterator();
		
		while(it.hasNext())
		{
			if(it.next().getForeground() == Color.red)
			{
				allAreSet = false;
			}
		}
		
		return allAreSet;
	}
	
	private void releaseKeyCodeIfNeeded(int keyCode)
	{
		Iterator<Entry<JButton, Integer>> it = m_CurrentMapping.entrySet().iterator();
		JButton buttonToUnset = null;
		
		while(it.hasNext())
		{
			Entry<JButton, Integer> e = it.next();
			
			if(e.getValue().intValue() == keyCode)
			{
				buttonToUnset = e.getKey();
			}
		}
		
		if(buttonToUnset != null)
		{
			m_CurrentMapping.put(buttonToUnset, new Integer(0));
		}
	}
	
	private HashMap<JButton, Integer> getHashMapClone(HashMap<JButton, Integer> original)
	{
		HashMap<JButton, Integer> clone = new HashMap<JButton, Integer>();
		Iterator<Entry<JButton, Integer>> it = original.entrySet().iterator();
		Entry<JButton, Integer> entry = null;
		
		while(it.hasNext())
		{
			entry = it.next();
			clone.put(entry.getKey(), entry.getValue());
		}
		
		return clone;
	}
	
	private void setButtonLabels()
	{
		Iterator<JButton> it = m_Buttons.iterator();
		JButton button = null;
		
		while(it.hasNext())
		{
			button = it.next();
			String stringRepresentaion = m_InputManager.getStringRepresentation(m_CurrentMapping.get(button).intValue());
			
			if(stringRepresentaion.equals("<NOT SET>"))
			{
				button.setForeground(Color.red);
			}
			else
			{
				button.setForeground(Color.black);
			}
			
			button.setText(button.getName() + stringRepresentaion);
		}
	}
	
	private void activateCurrentMapping()
	{
		m_InputManager.setUpperLeftKeyCode(m_CurrentMapping.get(m_UpperLeft));
		m_InputManager.setUpperRightKeyCode(m_CurrentMapping.get(m_UpperRight));
		m_InputManager.setMiddleLeftKeyCode(m_CurrentMapping.get(m_MiddleLeft));
		m_InputManager.setMiddleRightKeyCode(m_CurrentMapping.get(m_MiddleRight));
		m_InputManager.setLowerLeftKeyCode(m_CurrentMapping.get(m_LowerLeft));
		m_InputManager.setLowerRightKeyCode(m_CurrentMapping.get(m_LowerRight));
		m_InputManager.setMiddleRotateKeyCode(m_CurrentMapping.get(m_Rotate));
		m_InputManager.setLowerDropDownKeyCode(m_CurrentMapping.get(m_DropDown));
		m_InputManager.setPauseKeyCode(m_CurrentMapping.get(m_Pause));
		m_InputManager.setQuitKeyCode(m_CurrentMapping.get(m_Quit));
		
		m_LastMapping = this.getHashMapClone(m_CurrentMapping);
	}
}
